{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#  广播服务器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import List\n",
    "from twisted.internet.protocol import Protocol, Factory\n",
    "from twisted.internet.endpoints import TCP4ServerEndpoint\n",
    "from twisted.internet import reactor\n",
    "\n",
    "clients: List[Protocol] = []\n",
    "\n",
    "\n",
    "class ServerFactory(Factory):\n",
    "    def __init__(self):\n",
    "        self.numProtocols = 0\n",
    "\n",
    "    def buildProtocol(self, addr):\n",
    "        return Server(self)\n",
    "\n",
    "\n",
    "class Server(Protocol):\n",
    "    def __init__(self, factory: ServerFactory):\n",
    "        self.factory = factory\n",
    "\n",
    "    def connectionMade(self):\n",
    "        self.factory.numProtocols += 1\n",
    "        self.transport.write('您是第 {} 个客户端'.format(self.factory.numProtocols).encode('utf-8'))\n",
    "        print('new connect: {} - {}'.format(self.factory.numProtocols, self.transport.getPeer()))\n",
    "        clients.append(self)\n",
    "        print(clients)\n",
    "\n",
    "    def connectionLost(self, reason):\n",
    "        clients.remove(self)\n",
    "        print(\"Lost connect {}\".format(self))\n",
    "\n",
    "    def dataReceived(self, data):\n",
    "        if data == 'close':\n",
    "            self.transport.loseConnection()\n",
    "            print('server closed {}'.format(self))\n",
    "        else:\n",
    "            print('[ID: {}]>>> {}'.format(self, data))\n",
    "            for client in clients:\n",
    "                if client != self:\n",
    "                    client.transport.write(data)\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    endpoint = TCP4ServerEndpoint(reactor, 8007)\n",
    "    endpoint.listen(ServerFactory())\n",
    "    print(\"....等待链接..\")\n",
    "    reactor.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Twisted 客户端"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import datetime\n",
    "from twisted.internet.protocol import Protocol, ClientFactory\n",
    "from twisted.internet import reactor\n",
    "\n",
    "\n",
    "class Echo(Protocol):\n",
    "    def connectionMade(self):\n",
    "        print('Connected to the server!')\n",
    "\n",
    "    def dataReceived(self, data: bytes):\n",
    "        print('got message: ', data.decode('utf-8'))\n",
    "        reactor.callLater(2, self.say_hello)\n",
    "\n",
    "    def connectionLost(self, reason):\n",
    "        print(\"Disconnected from the server\")\n",
    "\n",
    "    def say_hello(self):\n",
    "        if self.transport.connected:\n",
    "            self.transport.write(\"hello, {}\".format(datetime.datetime.now()).encode('utf-8'))\n",
    "\n",
    "\n",
    "class EchoClientFactory(ClientFactory):\n",
    "    def __init__(self):\n",
    "        self.protocol = None\n",
    "\n",
    "    def startedConnecting(self, connector):\n",
    "        print('Started to connect.')\n",
    "\n",
    "    def buildProtocol(self, addr):\n",
    "        self.protocol = Echo()\n",
    "        return self.protocol\n",
    "\n",
    "    def clientConnectionLost(self, connector, reason):\n",
    "        print('Lost connection, Reason:', reason)\n",
    "\n",
    "    def clientConnectionFailed(self, connector, reason):\n",
    "        print('Connection fail, Reason:', reason)\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    host = '127.0.0.1'\n",
    "    port = 8007\n",
    "    factory = EchoClientFactory()\n",
    "    reactor.connectTCP(host, port, factory)\n",
    "    reactor.run()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
